#! /bin/bash
# Custom basic script to restore top level directories of a tape
# Queries the catalog files to display what's on the tape

PATH=$PATH:/bru
export PATH

. brufunclib

BLOCKSIZE_K=1024
LTO_INDEX=""
BRU_HOME=/Users/backupuser/bru
BRUTAB=${BRU_HOME}/etc/brutab
BRUXPAT=${BRU_HOME}/etc/bruxpat
RESTORE_PATHS_FILE=${BRU_HOME}/config/restorepaths

export BRUTAB
export BRUXPAT

echo ""
echo "****************** BRU LTO Restore Script ******************"
echo ""

fnSelectItems()
{
	INPUT="n"
	while [ $INPUT == "n" ]
	do
		echo -n "Enter the numbers of the items to restore (\"a\" for all, \"n\" to enter new tape index, \"q\" to quit):"
		read items
		echo $items | grep -E "^(([0-9]+|[0-9]+-[0-9]+)[[:space:]]*)+|a|n|q$" > /dev/null
        	if [ $? -eq 0 ]; then
			INPUT="y"
			if [ "$items" == "q" ]; then
				echo ""
				exit
			elif [ "$items" == "n" ]; then
				fnMain
				return 0
			elif [ "$items" == "a" ]; then
				echo "[ALL items on tape will be restored]"
				items=""
				n=0
				while [ $n -lt $num_items ]
				do
					items=$(echo -n "$items $[$n + 1]")
					n=$[$n + 1]
				done
			fi
			expanded_items=""
                	for item in $items; do
				echo $item | grep -E "^[0-9]+-[0-9]+$" > /dev/null
				if [ $? -eq 0 ]; then
					expanded_item=""
					start_num=$(echo "$item" | cut -f 1 -d '-')
					end_num=$(echo "$item" | cut -f 2 -d '-')
					if [ $start_num -gt $end_num ]; then
						temp=$start_num
						start_num=$end_num
						end_num=$temp
					fi
					for (( i = $start_num; i <= $end_num; i++ ))
					do
						expanded_item="$expanded_item $i"
					done
				else
					expanded_item=$item
				fi
				expanded_items="$expanded_items $expanded_item"
			done
			for item in $expanded_items; do
				if [ $item -gt $num_items -o $item -eq 0 ]; then
					echo "Index $item out of range"
					INPUT="n"
					break
				fi
			done
		fi
	done

	echo ""
	echo "The following items will be restored:"
	echo ""
	total_gb=0
	item_array=$(echo $expanded_items | tr ' ' '\n' | sort -nu )
	for a in $item_array; do
		echo "$a  ${name[$a]}  (${gb[$a]} GB)"
		total_gb=$(echo "scale=2; $total_gb + ${gb[$a]}" | bc)
	done
	echo ""
	echo "The total size of all files to be restored is $total_gb GB"
	echo ""
	echo "Available restore paths:"
	echo ""
	fnChoosePath $RESTORE_PATHS_FILE
	echo ""
	
	disk_space_k=$(df -k $SELECTED_PATH_NAME | tail -n1 | awk '{print $4}')
	disk_space_g=$(echo "scale=2; $disk_space_k / 1048576" | bc)

	echo "You have chosen to restore all files to: $SELECTED_PATH_NAME ($disk_space_g GB available)"
	cd "$SELECTED_PATH_NAME"
}


fnLookup()
{
	IS_NUM="n"
	while [ $IS_NUM == "n" ]
	do
		echo -n "Enter tape index number:"
		read LTO_INDEX
		echo $LTO_INDEX | grep "^[34][0-9][0-9][0-9]$" > /dev/null
		if [ $? -eq 0 ]; then
			IS_NUM="y"
		fi
	done

	match="n"
	for f in ${BRU_HOME}/catalog/BRU-*.gz; do
		count=$(gzcat $f | wc -l | tr -d " ")
		archive_label=$(gzcat $f | head -n 2 | tail -n 1 | cut -f 3 -d " ")
		if [ $LTO_INDEX == $archive_label ]; then

			archive_id=$(gzcat $f | head -n 1 | cut -f 4 -d " ")			

			contents=$(gzcat $f | tail +5 | head -n $[$count - 21] | cut -f 1 -d "/" | awk -F\| '{if (!x[$6]++) print $5 " " $6}')

			# Need to parse last line differently to calculate size of last file
			tape_used_k=$(gzcat $f | tail -n 17 | head -n 1 | cut -f 2 -d "(" | cut -f 1 -d " ")
			
			match="y"
			break
		fi
	done

	if [ $match == "n" ]; then
		echo "Index for tape $LTO_INDEX could not be found."
		fnMain
		return 0
	fi

	echo ""

	count=1
	OLDIFS=$IFS
	IFS=$'\n'
	for line in $contents; do
		name[$count]=$(echo "$line" | cut -f 2 -d ' ')
		block[$count]=$(echo "$line" | cut -f 1 -d ' ')
		count=$[$count + 1]
	done

	num_items=$[$count - 1]
	block[$[$num_items + 1]]=$[$tape_used_k / 1024]

	tape_used_g=$(echo "scale=1; ${block[$[$num_items + 1]]} / 1024" | bc)

	echo "BRU ID: $archive_id"
	echo ""

	for (( i=1; i<=$num_items; i++ )); do
		mb[$i]=$[${block[$[$i + 1]]} - ${block[$i]}]
		gb[$i]=$(echo "scale=1; ${mb[$i]} / 1024" | bc)

		# Could reduce sizes by about 12% to account for checksumming data - so reported filesizes will not be EXACT
		# gb_reduced[$i]=$(echo "scale=1; ${gb[$i]} * 88 / 100" | bc) 
		# For now we'll report the sizes of the BRU data

		echo "$i  ${name[$i]}  (${gb[$i]} GB)"
	done
	IFS=$OLDIFS
	echo ""
	echo $tape_used_g "GB total written to tape"
	echo ""
}

fnIndexMatchCheck()
{
	# Check tape label matches
	if [ $LABEL != $LTO_INDEX ]; then
		echo ""
		echo "The label of the inserted tape ($LABEL) does not match the selected index ($LTO_INDEX)"
		if [ $TRIED_BOTH_DRIVES == "FALSE" ]; then
			echo ""
			echo "Trying other drive ..."
			fnLoadTape $[ ($CURRENT_DRIVE + 1) % 2 ] "FALSE" "ON"
			TRIED_BOTH_DRIVES="TRUE"
			fnLoadCheck
			fnCheckTapeLabel $CURRENT_DRIVE
			fnIndexMatchCheck
			return 0
		else
			echo ""
			echo "Could not locate tape $LTO_INDEX"
			fnMain
			return 0
		fi
	else
                echo "Located tape $LABEL in drive $CURRENT_DRIVE"
		fnRestore $CURRENT_DRIVE
	fi
}

fnTapeCheck()
{
	if [ $LOAD_STATUS == "DRIVE_EMPTY" ]; then
		if [ $TRIED_BOTH_DRIVES == "TRUE" ]; then
			fnMain
			return 0
		else
			fnLoadTape 1 "FALSE" "ON"
			TRIED_BOTH_DRIVES="TRUE"
			fnTapeCheck
		fi
	fi

	if [ $LOAD_STATUS == "TAPE_NOT_PROTECTED" ]; then
		echo "Please write protect tape before proceeding"
		echo ""
		echo "Ejecting tape in drive $CURRENT_DRIVE ..."
		fnEjectTape $CURRENT_DRIVE
		fnMain 
		return 0
	fi	

	fnCheckTapeLabel $CURRENT_DRIVE
	fnIndexMatchCheck
}

fnMain()
{	
	echo ""
	echo "Please ensure that tape $LTO_INDEX is inserted into any drive"
	echo -n "(press Enter to continue, \"q\" to quit, or \"s\" to re-select items)"
	read INPUT
	echo $INPUT | grep -E "^q|s$" > /dev/null
        if [ $? -eq 0 ]; then
		if [ $INPUT == "q" ]; then
			echo ""
			exit
		elif [ $INPUT == "s" ]; then
			echo ""
			fnSelectItems
			fnMain
		fi
	fi

	TRIED_BOTH_DRIVES="FALSE"
	fnLoadTape 0 "FALSE" "ON"
	fnTapeCheck
}

fnRestore()
{	
	# Run BRU restore data script

	echo ""
	echo "Restoring files ..."
	echo ""
	fnRewindTape $1

	for a in $item_array; do
		if [ ${block[$a]} -gt 0 ]; then
			echo "Seeking to block $[${block[$a]} - 1]"
        		tapectl -v -f ntape$1 seek $[${block[$a]} - 1]
		else
			echo "Seeking to block 0"
        		tapectl -v -f ntape$1 seek 0
		fi
		echo "Restoring ${name[$a]}"
		bru -xvvvvvvvvv -f ntape$1 -b ${BLOCKSIZE_K}k -QV ${name[$a]}
		echo ""
	done
	
	echo "Rewinding tape ..."
	fnRewindTape $1
	echo "Ejecting tape ..."
	fnEjectTape $1

	echo ""
	echo "DONE!"
	echo ""
	echo -n "Press Enter to continue restoring more files, or q to quit"
	read INPUT
	echo $INPUT | grep "^q$" > /dev/null
        if [ $? -eq 0 ]; then
		echo ""
		exit
	else
		fnLookup
	fi
}

fnLookup
fnSelectItems
fnMain



